﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using App1AppHandler;
using System.Data.SqlClient;
using System.Data;
using Reborn_Server.App1AppHandler;
using System.Threading;
using System.Reflection;

namespace Reborn_WorldServer.App1AppHandler
{
    public class MapLocks
    {
        //Collection of objects used to lock maps for thread safety
        Dictionary<string, LockItem> lockItems = new Dictionary<string, LockItem>();

        bool requireLock = false;
        Object masterLock = new Object();

        int nonLockingActiveThreads = 0;

        public LockItem getLockItem(int mapId, int instance)
        {
            bool lockUsed = false;
            bool notFound = false;

            //Record that this thread is running non locked, increment a counter            
            if (requireLock == false)
                Interlocked.Increment(ref nonLockingActiveThreads);
            //If something is trying to modify this, lock will be required
            else
            {
                Monitor.Enter(masterLock);
                lockUsed = true;
            }

            //Sensitive code, we cannot modify this unless lock is enabled
            LockItem lockObj;
            if (lockItems.TryGetValue(mapId.ToString() + "," + instance.ToString(), out lockObj) == false)
                notFound = true;

            //Release lock, or remove the non locking thread counter
            if (lockUsed)
                Monitor.Exit(masterLock);
            else
                Interlocked.Decrement(ref nonLockingActiveThreads);

            if (notFound)
            {
                //Aquire Lock
                Monitor.Enter(masterLock);

                //Try to get the lock again incase multiple threads were waiting to create this lock.
                if (lockItems.TryGetValue(mapId.ToString() + "," + instance.ToString(), out lockObj) == true)
                {
                    Monitor.Exit(masterLock);
                    return lockObj;
                }

                //Start requiring lock to read
                requireLock = true;

                //Wait for any non locked threads to finish
                while (nonLockingActiveThreads > 0)
                    System.Threading.Thread.Sleep(10);

                lockObj = new LockItem();
                lockObj.MapID = mapId;
                lockObj.MapInstance = instance;

                lockItems.Add(mapId.ToString() + "," + instance.ToString(), lockObj);
                createMap(mapId, instance);

                //Done modifying, no longer require lock to read
                requireLock = false;

                Monitor.Exit(masterLock);
            }

            return lockObj;
        }

        private void createMap(int MapID, int Instance)
        {
            AppHandler2 app = Managers.GameHandler;

            Map NewMap = new Map(app);
            NewMap.MapID = MapID;
            NewMap.MapInstance = Instance;

            SqlConnection MyCon = new SqlConnection(Managers.DBConnectionString);
            SqlCommand SQLCom;
            SqlDataReader SDR;

            //GET START POSITION FOR MAP
            SQLCom = new SqlCommand("MapNames_Select", MyCon);
            SQLCom.CommandType = System.Data.CommandType.StoredProcedure;
            SQLCom.Parameters.AddWithValue("@MapID", MapID);

            MyCon.Open();
            SDR = SQLCom.ExecuteReader();
            while (SDR.Read())
            {
                NewMap.StartMapX = int.Parse(SDR["StartMapX"].ToString());
                NewMap.StartMapY = int.Parse(SDR["StartMapY"].ToString());
                NewMap.StartMapID = int.Parse(SDR["StartMapID"].ToString());
            }
            SDR.Close();
            //MyCon.Close();

            //GET MAPITEMS
            SQLCom = new SqlCommand("Map_Select", MyCon);
            SQLCom.CommandType = System.Data.CommandType.StoredProcedure;
            SQLCom.Parameters.AddWithValue("@MapID", MapID);

            //MyCon.Open();
            SDR = SQLCom.ExecuteReader();
            while (SDR.Read())
            {
                MapItem mapitem = new MapItem();

                mapitem.ColorUrl = SDR["ColorUrl"].ToString();
                mapitem.TerrainUrl = SDR["TerrainUrl"].ToString();
                mapitem.Motion = int.Parse(SDR["Motion"].ToString());
                mapitem.Transparent = bool.Parse(SDR["Transparent"].ToString());
                mapitem.TerrainType = SDR["TerrainType"].ToString();
                mapitem.MapX = int.Parse(SDR["MapX"].ToString());
                mapitem.MapY = int.Parse(SDR["MapY"].ToString());

                if (SDR["Terrain2"] != DBNull.Value)
                    mapitem.Terrain2 = SDR["Terrain2"].ToString();
                if (SDR["TerrainOver"] != DBNull.Value)
                    mapitem.TerrainOver = SDR["TerrainOver"].ToString();

                if (SDR["PortalMapID"] != DBNull.Value)
                    mapitem.PortalMapID = int.Parse(SDR["PortalMapID"].ToString());
                if (SDR["PortalX"] != DBNull.Value)
                    mapitem.PortalX = int.Parse(SDR["PortalX"].ToString());
                if (SDR["PortalY"] != DBNull.Value)
                    mapitem.PortalY = int.Parse(SDR["PortalY"].ToString());
                if (SDR["PortalDistance"] != DBNull.Value)
                    mapitem.PortalDistance = int.Parse(SDR["PortalDistance"].ToString());
                if (SDR["PortalLevelRequirement"] != DBNull.Value)
                    mapitem.PortalLevelRequirement = int.Parse(SDR["PortalLevelRequirement"].ToString());
                if (SDR["PortalSkillType"] != DBNull.Value)
                    mapitem.PortalSkillType = SDR["PortalSkillType"].ToString();
                if (SDR["AllowAOE"] != DBNull.Value)
                    mapitem.allowAOE = bool.Parse(SDR["AllowAOE"].ToString());
                if (SDR["Dark"] != DBNull.Value)
                    mapitem.isNaturalDark = bool.Parse(SDR["Dark"].ToString());

                mapitem.parentMap = NewMap;

                NewMap.MapItems.Add(mapitem);
            }
            SDR.Close();
            //MyCon.Close();

            foreach (MapItem masterMapItem in NewMap.MapItems)
            {
                foreach (MapItem mapItem in NewMap.MapItems)
                {
                    if (Math.Abs(mapItem.MapX - masterMapItem.MapX) <= 12 && Math.Abs(mapItem.MapY - masterMapItem.MapY) <= 12)
                    {
                        masterMapItem.mapItemsWithin12.Add(mapItem);
                        if (Math.Abs(mapItem.MapX - masterMapItem.MapX) <= 8 && Math.Abs(mapItem.MapY - masterMapItem.MapY) <= 8)
                        {
                            masterMapItem.mapItemsWithin8.Add(mapItem);
                            if (Math.Abs(mapItem.MapX - masterMapItem.MapX) <= 4 && Math.Abs(mapItem.MapY - masterMapItem.MapY) <= 4)
                                masterMapItem.mapItemsWithin4.Add(mapItem);
                        }
                    }
                }
            }

            Managers.GameHandler.Maps.Add(NewMap);

            //Create Ground Spawn Items
            SQLCom = new SqlCommand("Map_GroundSpawns_Select", MyCon);
            SQLCom.CommandType = CommandType.StoredProcedure;
            SQLCom.Parameters.AddWithValue("@MapID", MapID);
            SDR = SQLCom.ExecuteReader();

            while (SDR.Read())
            {
                Loot groundSpawnItem = Managers.GameHandler.CreateItem(int.Parse(SDR["ItemID"].ToString()));
                groundSpawnItem.isGroundSpawn = true;
                groundSpawnItem.respawnMinutes = int.Parse(SDR["RespawnMinutes"].ToString());

                int dropX = int.Parse(SDR["MapX"].ToString());
                int dropY = int.Parse(SDR["MapY"].ToString());

                NewMap.LootMngr.DropItems(dropX, dropY, groundSpawnItem, false);
            }
            SDR.Close();

            //CREATE LIST OF ALL CREATURES
            List<Creature> MapCreatures = new List<Creature>();

            SQLCom = new SqlCommand("Creatures_SelectByMapID", MyCon);
            SQLCom.CommandType = CommandType.StoredProcedure;
            SQLCom.Parameters.AddWithValue("@MapID", MapID);
            SDR = SQLCom.ExecuteReader();
            while (SDR.Read())
            {
                //Create the correct type of creature
                Creature newCrit = null;
                if (SDR["CreatureType"].ToString() == "Trainer")
                {
                    Trainer newTrainer = new Trainer(app);
                    newCrit = (Creature)newTrainer;
                }
                else if (SDR["CreatureType"].ToString() == "Vendor")
                {
                    Vendor newVendor = new Vendor(app);
                    newCrit = (Creature)newVendor;
                }
                else if (SDR["CreatureType"].ToString() == "QuestCreature")
                {
                    QuestCreature newQuestCrit = new QuestCreature(app);
                    newCrit = (Creature)newQuestCrit;
                }
                else if (SDR["CreatureType"].ToString() == "Banker")
                {
                    Banker newBanker = new Banker(app);
                    newCrit = (Creature)newBanker;
                }
                else
                {
                    if (SDR["CustomCreatureClass"] != DBNull.Value && SDR["CustomCreatureClass"].ToString() != "")
                    {
                        Assembly assembly = Assembly.GetExecutingAssembly();
                        string fullTypeName = "App1AppHandler" + "." + SDR["CustomCreatureClass"].ToString();
                        Type myType = assembly.GetType(fullTypeName);

                        Object[] args = { app };

                        object ClassObj = Activator.CreateInstance(myType, args);

                        newCrit = (Creature)ClassObj;
                    }
                    //Standard creature
                    else
                        newCrit = new Creature(app);
                }

                newCrit.CreatureType = SDR["CreatureType"].ToString();
                newCrit.CreatureID = Managers.GameHandler.ItemIDGen.GetCreatureUID();
                newCrit.ID = int.Parse(SDR["ID"].ToString());

                newCrit.HPRegen = int.Parse(SDR["HPRegen"].ToString());
                newCrit.ManaRegen = int.Parse(SDR["ManaRegen"].ToString());

                if (SDR["WaterMotion"] != DBNull.Value)
                    newCrit.WaterMotion = int.Parse(SDR["WaterMotion"].ToString());

                newCrit.MaxHPBase = int.Parse(SDR["MaxHP"].ToString());
                newCrit.MaxStaminaBase = int.Parse(SDR["MaxStamina"].ToString());
                newCrit.MaxManaBase = int.Parse(SDR["MaxMana"].ToString());
                newCrit.StartMapX = int.Parse(SDR["StartMapX"].ToString());
                newCrit.StartMapY = int.Parse(SDR["StartMapY"].ToString());
                newCrit.StartMapID = MapID;
                newCrit.Instance = Instance;

                if (SDR["StartLeftHand"] != DBNull.Value)
                    newCrit.StartLeftHand = int.Parse(SDR["StartLeftHand"].ToString());
                if (SDR["StartRightHand"] != DBNull.Value)
                    newCrit.StartRightHand = int.Parse(SDR["StartRightHand"].ToString());

                newCrit.Air = bool.Parse(SDR["Air"].ToString());
                newCrit.Water = bool.Parse(SDR["Water"].ToString());
                newCrit.Land = bool.Parse(SDR["Land"].ToString());

                newCrit.CorpseImageURL = SDR["CorpseImageURL"].ToString();

                newCrit.Faction = SDR["Faction"].ToString();

                newCrit.ImageURL = SDR["ImageURL"].ToString();
                newCrit.MaxMoves = int.Parse(SDR["MaxMoves"].ToString());
                newCrit.Name = SDR["Name"].ToString();
                newCrit.Respawn_Min = int.Parse(SDR["Respawn_Min"].ToString());
                newCrit.SoundDeath = SDR["SoundDeath"].ToString();

                if (SDR["WanderMax_N"] != DBNull.Value)
                    newCrit.WanderMax_N = int.Parse(SDR["WanderMax_N"].ToString());
                if (SDR["WanderMax_E"] != DBNull.Value)
                    newCrit.WanderMax_E = int.Parse(SDR["WanderMax_E"].ToString());
                if (SDR["WanderMax_S"] != DBNull.Value)
                    newCrit.WanderMax_S = int.Parse(SDR["WanderMax_S"].ToString());
                if (SDR["WanderMax_W"] != DBNull.Value)
                    newCrit.WanderMax_W = int.Parse(SDR["WanderMax_W"].ToString());

                newCrit.CoinsLow = int.Parse(SDR["CoinsLow"].ToString());
                newCrit.CoinsHigh = int.Parse(SDR["CoinsHigh"].ToString());

                newCrit.buffManager.HasInnateNightVision = bool.Parse(SDR["HasNightVision"].ToString());

                newCrit.RushAttack = bool.Parse(SDR["RushAttack"].ToString());
                newCrit.RangeAttack = bool.Parse(SDR["RangeAttack"].ToString());

                newCrit.Defense = int.Parse(SDR["Defense"].ToString());

                if (SDR["DefenseSkill"] != DBNull.Value)
                    newCrit.DefenseSkill = int.Parse(SDR["DefenseSkill"].ToString());
                if (SDR["HandBlockWeapon"] != DBNull.Value)
                    newCrit.HandBlockWeapon = SDR["HandBlockWeapon"].ToString();
                if (SDR["SoundEnterCombat"] != DBNull.Value)
                    newCrit.SoundEnterCombat = SDR["SoundEnterCombat"].ToString();
                if (SDR["MovementSpeed"] != DBNull.Value)
                {
                    newCrit.MovementSpeed = double.Parse(SDR["MovementSpeed"].ToString());
                    newCrit.BaseMovementSpeed = double.Parse(SDR["MovementSpeed"].ToString());
                }
                if (SDR["RunHPPercent"] != DBNull.Value)
                    newCrit.RunHPPercent = int.Parse(SDR["RunHPPercent"].ToString());

                if (SDR["Intelligence"] != DBNull.Value)
                    newCrit.Intelligence = int.Parse(SDR["Intelligence"].ToString());
                if (SDR["Wisdom"] != DBNull.Value)
                    newCrit.Wisdom = int.Parse(SDR["Wisdom"].ToString());
                if (SDR["Strength"] != DBNull.Value)
                    newCrit.Strength = int.Parse(SDR["Strength"].ToString());
                if (SDR["Agility"] != DBNull.Value)
                    newCrit.Agility = int.Parse(SDR["Agility"].ToString());
                if (SDR["Dexterity"] != DBNull.Value)
                    newCrit.Dexterity = int.Parse(SDR["Dexterity"].ToString());

                //Currently ResistFire will get modified. We need to also track the origional value in BaseResistFire which will never change.
                if (SDR["ResistFire"] != DBNull.Value)
                {
                    newCrit.ResistFire = int.Parse(SDR["ResistFire"].ToString());
                    newCrit.BaseResistFire = int.Parse(SDR["ResistFire"].ToString());
                }
                if (SDR["ResistIce"] != DBNull.Value)
                {
                    newCrit.ResistIce = int.Parse(SDR["ResistIce"].ToString());
                    newCrit.BaseResistIce = int.Parse(SDR["ResistIce"].ToString());
                }
                if (SDR["ResistHoly"] != DBNull.Value)
                {
                    newCrit.ResistHoly = int.Parse(SDR["ResistHoly"].ToString());
                    newCrit.BaseResistHoly = int.Parse(SDR["ResistHoly"].ToString());
                }
                if (SDR["ResistUnholy"] != DBNull.Value)
                {
                    newCrit.ResistUnholy = int.Parse(SDR["ResistUnholy"].ToString());
                    newCrit.BaseResistUnholy = int.Parse(SDR["ResistUnholy"].ToString());
                }
                if (SDR["ResistMagic"] != DBNull.Value)
                {
                    newCrit.ResistMagic = int.Parse(SDR["ResistMagic"].ToString());
                    newCrit.BaseResistMagic = int.Parse(SDR["ResistMagic"].ToString());
                }
                if (SDR["ResistPhysical"] != DBNull.Value)
                {
                    newCrit.ResistPhysical = int.Parse(SDR["ResistPhysical"].ToString());
                    newCrit.BaseResistPhysical = int.Parse(SDR["ResistPhysical"].ToString());
                }

                if (SDR["IgnoresFire"] != DBNull.Value)
                    newCrit.IgnoresFire = bool.Parse(SDR["IgnoresFire"].ToString());
                if (SDR["IgnoresIce"] != DBNull.Value)
                    newCrit.IgnoresIce = bool.Parse(SDR["IgnoresIce"].ToString());
                if (SDR["IgnoresHoly"] != DBNull.Value)
                    newCrit.IgnoresHoly = bool.Parse(SDR["IgnoresHoly"].ToString());
                if (SDR["IgnoresUnholy"] != DBNull.Value)
                    newCrit.IgnoresUnholy = bool.Parse(SDR["IgnoresUnholy"].ToString());
                if (SDR["IgnoresMagic"] != DBNull.Value)
                    newCrit.IgnoresMagic = bool.Parse(SDR["IgnoresMagic"].ToString());

                if (SDR["Smart"] != DBNull.Value)
                    newCrit.Smart = bool.Parse(SDR["Smart"].ToString());

                if (SDR["XmlData"] != DBNull.Value)
                    newCrit.setXmlData(SDR["XmlData"].ToString());

                newCrit.BaseArmor = int.Parse(SDR["Armor"].ToString());
                newCrit.Armor = int.Parse(SDR["Armor"].ToString());

                MapCreatures.Add(newCrit);
                
                NewMap.numCreatures++;
            }
            SDR.Close();

            //used to spread out the creature's rounds, so they dont all start up moving together.
            double creatureStartSpread = 0;

            //Get additional data for special creatures and add creatures to map
            foreach (Creature creature in MapCreatures)
            {
                if (creature.CreatureType == "Trainer")
                {
                    Trainer trainer = (Trainer)creature;

                    //Get Trainer's Skill
                    SQLCom = new SqlCommand("Trainers_SelectByCreatureID", MyCon);
                    SQLCom.CommandType = CommandType.StoredProcedure;
                    SQLCom.Parameters.AddWithValue("@CreatureID", trainer.ID);

                    SDR = SQLCom.ExecuteReader();
                    if (SDR.Read())
                    {
                        if (SDR["TrainsSkill"] != System.DBNull.Value)
                            trainer.TrainsSkill = SDR["TrainsSkill"].ToString();
                    }
                    SDR.Close();

                    //Get Trainer's Spells
                    SQLCom = new SqlCommand("Trainers_Spells_SelectByCreatureID", MyCon);
                    SQLCom.CommandType = System.Data.CommandType.StoredProcedure;
                    SQLCom.Parameters.AddWithValue("@TrainerID", trainer.ID);

                    SDR = SQLCom.ExecuteReader();
                    while (SDR.Read())
                    {
                        TrainerSpell trainerSpell = new TrainerSpell();
                        trainerSpell.spellIcon = Managers.GameHandler.Spells[int.Parse(SDR["SpellID"].ToString())];
                        trainerSpell.overrideCost = int.Parse(SDR["OverrideCost"].ToString());
                        trainer.TrainerSpells.Add(trainerSpell);
                    }
                    SDR.Close();


                    //Get Trainer's Weapon Skills
                    SQLCom = new SqlCommand("Trainers_WeaponSkills_SelectByCreatureID", MyCon);
                    SQLCom.CommandType = System.Data.CommandType.StoredProcedure;
                    SQLCom.Parameters.AddWithValue("@TrainerID", trainer.ID);

                    SDR = SQLCom.ExecuteReader();
                    while (SDR.Read())
                    {
                        TrainerWeaponSkill trainerWeaponSkill = new TrainerWeaponSkill();
                        trainerWeaponSkill.weaponSkill = Managers.GameHandler.WeaponSkills[int.Parse(SDR["WeaponSkillID"].ToString())];
                        trainerWeaponSkill.overrideCost = int.Parse(SDR["OverrideCost"].ToString());

                        trainer.TrainerWeaponSkills.Add(trainerWeaponSkill);
                    }
                    SDR.Close();

                    NewMap.addTrainer(trainer);
                }
                else if (creature.CreatureType == "Vendor")
                {
                    Vendor vendor = (Vendor)creature;

                    //Get Vendors Price Adjustments
                    SQLCom = new SqlCommand("Vendors_SelectByCreatureID", MyCon);
                    SQLCom.CommandType = CommandType.StoredProcedure;
                    SQLCom.Parameters.AddWithValue("@CreatureID", vendor.ID);

                    SDR = SQLCom.ExecuteReader();
                    if (SDR.Read())
                    {
                        if (SDR["PriceAdjustPercentLow"] != System.DBNull.Value)
                            vendor.PriceAdjustPercentLow = int.Parse(SDR["PriceAdjustPercentLow"].ToString());
                        if (SDR["PriceAdjustPercentHigh"] != System.DBNull.Value)
                            vendor.PriceAdjustPercentHigh = int.Parse(SDR["PriceAdjustPercentHigh"].ToString());
                    }
                    SDR.Close();

                    //Get Vendors Items for sale
                    SQLCom = new SqlCommand("Vendors_LootItems_SelectByCreatureID", MyCon);
                    SQLCom.CommandType = System.Data.CommandType.StoredProcedure;
                    SQLCom.Parameters.AddWithValue("@VendorID", vendor.ID);
                    SDR = SQLCom.ExecuteReader();
                    while (SDR.Read())
                    {
                        Loot loot = Managers.GameHandler.CreateItem(int.Parse(SDR["ItemID"].ToString()));
                        vendor.VendorLootItems.Add(loot);
                    }
                    SDR.Close();

                    NewMap.addVendor(vendor);
                }
                else if (creature.CreatureType == "QuestCreature")
                {
                    QuestCreature questCreature = (QuestCreature)creature;

                    //Get Quest Data
                    SQLCom = new SqlCommand("QuestCreatures_SelectByCreatureID", MyCon);
                    SQLCom.CommandType = CommandType.StoredProcedure;
                    SQLCom.Parameters.AddWithValue("@CreatureID", questCreature.ID);

                    SDR = SQLCom.ExecuteReader();

                    if (SDR.Read())
                    {
                        if (SDR["QuestStartDialog"] != System.DBNull.Value)
                            questCreature.QuestStartDialog = SDR["QuestStartDialog"].ToString();
                        if (SDR["QuestFinishDialog"] != System.DBNull.Value)
                            questCreature.QuestFinishDialog = SDR["QuestFinishDialog"].ToString();

                        questCreature.RewardsAll = bool.Parse(SDR["RewardsAll"].ToString());
                        questCreature.QuestType = SDR["QuestType"].ToString();

                        if (SDR["EscortDestinationN"] != System.DBNull.Value)
                            questCreature.EscortDestinationN = int.Parse(SDR["EscortDestinationN"].ToString());
                        if (SDR["EscortDestinationE"] != System.DBNull.Value)
                            questCreature.EscortDestinationE = int.Parse(SDR["EscortDestinationE"].ToString());
                        if (SDR["EscortDestinationS"] != System.DBNull.Value)
                            questCreature.EscortDestinationS = int.Parse(SDR["EscortDestinationS"].ToString());
                        if (SDR["EscortDestinationW"] != System.DBNull.Value)
                            questCreature.EscortDestinationW = int.Parse(SDR["EscortDestinationW"].ToString());
                        if (SDR["EscortMapID"] != System.DBNull.Value)
                            questCreature.EscortMapID = int.Parse(SDR["EscortMapID"].ToString());
                    }
                    SDR.Close();

                    if (questCreature.QuestType == "Collection")
                    {
                        //Collection quests are always in complete status
                        questCreature.QuestStatus = "Complete";

                        //Get required collection items
                        SQLCom = new SqlCommand("QuestCreatures_QuestItems_SelectByCreatureID", MyCon);
                        SQLCom.CommandType = System.Data.CommandType.StoredProcedure;
                        SQLCom.Parameters.AddWithValue("@CreatureID", questCreature.ID);
                        SQLCom.Parameters.AddWithValue("@QuestItemType", "Collection");

                        SDR = SQLCom.ExecuteReader();

                        while (SDR.Read())
                            questCreature.CollectionItems.Add(Managers.GameHandler.Items[int.Parse(SDR["ItemID"].ToString())]);

                        SDR.Close();
                    }

                    //Get reward Items
                    SQLCom = new SqlCommand("QuestCreatures_QuestItems_SelectByCreatureID", MyCon);
                    SQLCom.CommandType = System.Data.CommandType.StoredProcedure;
                    SQLCom.Parameters.AddWithValue("@CreatureID", questCreature.ID);
                    SQLCom.Parameters.AddWithValue("@QuestItemType", "Reward");

                    SDR = SQLCom.ExecuteReader();
                    while (SDR.Read())
                        questCreature.RewardItems.Add(Managers.GameHandler.Items[int.Parse(SDR["ItemID"].ToString())]);

                    SDR.Close();
                }

                //Get Loot Drops
                SQLCom = new SqlCommand("Creatures_DropLoot_SelectByCreatureID", MyCon);
                SQLCom.CommandType = System.Data.CommandType.StoredProcedure;
                SQLCom.Parameters.AddWithValue("@CreatureID", creature.ID);

                SDR = SQLCom.ExecuteReader();
                while (SDR.Read())
                {
                    LootDrop lootDrop = new LootDrop();
                    lootDrop.IsUnique = bool.Parse(SDR["IsUnique"].ToString());
                    lootDrop.LootDropRate = int.Parse(SDR["Rate"].ToString());
                    lootDrop.LootID = int.Parse(SDR["LootID"].ToString());

                    creature.LootDrops.Add(lootDrop);
                }
                SDR.Close();

                //Get Attacks Sequence
                SQLCom = new SqlCommand("Creatures_AttackWeapons_SelectByCreatureID", MyCon);
                SQLCom.CommandType = System.Data.CommandType.StoredProcedure;
                SQLCom.Parameters.AddWithValue("@CreatureID", creature.ID);

                SDR = SQLCom.ExecuteReader();
                while (SDR.Read())
                {
                    CreatureAttackWeapon caw = new CreatureAttackWeapon();

                    caw.Accuracy = int.Parse(SDR["Accuracy"].ToString());
                    caw.Description = SDR["Description"].ToString();
                    caw.DmgHigh = int.Parse(SDR["DmgHigh"].ToString());
                    caw.DmgLow = int.Parse(SDR["DmgLow"].ToString());
                    caw.Frequency = int.Parse(SDR["Frequency"].ToString());
                    caw.Sequence = int.Parse(SDR["Sequence"].ToString());
                    caw.SkillLevel = int.Parse(SDR["SkillLevel"].ToString());
                    caw.Speed = decimal.Parse(SDR["Speed"].ToString());

                    creature.attackSequenceManager.Attacks.Add(caw);
                }
                SDR.Close();
                //Make sure every creature has a melee attack or server will crash (Incase creature is not set up correctly in creature editor)
                if (creature.attackSequenceManager.Attacks.Count == 0)
                {
                    CreatureAttackWeapon handWeapon = new CreatureAttackWeapon();
                    handWeapon.Accuracy = 50;
                    handWeapon.Description = "punches {name}";
                    handWeapon.DmgHigh = 20;
                    handWeapon.DmgLow = 10;
                    handWeapon.Frequency = 1;
                    handWeapon.Sequence = 1;
                    handWeapon.SkillLevel = 1;
                    handWeapon.Speed = 2;

                    creature.attackSequenceManager.Attacks.Add(handWeapon);
                }


                //Get Spells Sequence
                SQLCom = new SqlCommand("Creatures_CastSpells_SelectByCreatureID", MyCon);
                SQLCom.CommandType = System.Data.CommandType.StoredProcedure;
                SQLCom.Parameters.AddWithValue("@CreatureID", creature.ID);

                SDR = SQLCom.ExecuteReader();
                while (SDR.Read())
                {
                    CreatureCastSpell ccs = new CreatureCastSpell();

                    ccs.Frequency = int.Parse(SDR["Frequency"].ToString());
                    ccs.Sequence = int.Parse(SDR["Sequence"].ToString());
                    ccs.SkillLevel = int.Parse(SDR["SkillLevel"].ToString());
                    ccs.spellIcon = Managers.GameHandler.Spells[int.Parse(SDR["SpellID"].ToString())];
                    ccs.Instant = bool.Parse(SDR["Instant"].ToString());
                    ccs.allowAllyAttackCount = int.Parse(SDR["AllowAllyAttackCount"].ToString());

                    creature.attackSequenceManager.Spells.Add(ccs);
                }
                SDR.Close();

                //Get Spells Sequence
                SQLCom = new SqlCommand("Creatures_StackTypeImmunities_SelectByCreatureID", MyCon);
                SQLCom.CommandType = System.Data.CommandType.StoredProcedure;
                SQLCom.Parameters.AddWithValue("@CreatureID", creature.ID);

                SDR = SQLCom.ExecuteReader();
                while (SDR.Read())
                {
                    creature.stackTypeImmunities.Add(SDR["StackType"].ToString());
                }
                SDR.Close();

                //Copy this creatures base setup.
                Creature templateCreature = new Creature(app);
                templateCreature.copyFrom(creature);

                //Save this as a template. For summoning new instances of existing creatures.
                Managers.GameHandler.AllCreatures[creature.ID] = templateCreature;

                //Reset the creature and add it to the map
                creature.ResetCreature();
                foreach (MapItem mapItem in NewMap.MapItems)
                {
                    if (mapItem.MapX == creature.StartMapX && mapItem.MapY == creature.StartMapY)
                    {
                        creature.SetPosition(mapItem);
                        mapItem.CreaturesBases.Add(creature);
                        break;
                    }
                }

                //If this is a regular creature, start its AI and Regen
                if (creature.CreatureType == "Creature")
                {
                    creatureStartSpread = creatureStartSpread + 100;
                    if (creatureStartSpread >= 1000)
                        creatureStartSpread = 0;

                    creature.creatureAI.Timer_CreatureRound.StartWithOffset(creatureStartSpread);
                    creature.Timer_Regen.Start();
                }
            }

            //All done with the SQL Server
            MyCon.Close();
            MyCon.Dispose();
        }
    }
}
